package com.hy.example.shared.dbaccess.repository;

import jakarta.persistence.Entity;

import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.Filer;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.TypeElement;
import javax.tools.Diagnostic;
import java.io.IOException;
import java.io.Writer;
import java.util.Set;

/**
 * 自动生成 实体对应的 Repository 类， 默认使用 Long 的实体KEY
 */
@SupportedAnnotationTypes({"jakarta.persistence.Entity"})
public class DBAccessRepositoryProcessor extends AbstractProcessor {
    private static final String REPOSITORY_TEMPLATE = """
            package %1$s; //package name

            import com.hy.example.shared.dbaccess.repository.DBAccessRepository;
            import %2$s; // domain entity class full name
            import org.springframework.stereotype.Repository;

            @Repository
            public interface %3$sRepository // repository name
                    extends DBAccessRepository<%4$s> { // domain entity class simple name, domain id class simple name
            }
                """;

    @Override
    public SourceVersion getSupportedSourceVersion() {
        return SourceVersion.latestSupported();
    }

    @Override
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
        for (Element element : roundEnv.getElementsAnnotatedWith(Entity.class)) {
            TypeElement typeElement = (TypeElement) element;
            Filer filer = processingEnv.getFiler();
            try (Writer sw = filer.createSourceFile(guessWriteFileName(typeElement)).openWriter()) {
                processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE,
                        "Generating " + guessDomainClassFullName(typeElement) + " Repository source code");
                sw.write(String.format(REPOSITORY_TEMPLATE,
                        guessPackageName(typeElement), guessDomainClassFullName(typeElement),
                        guessRepositorySimpleName(typeElement), guessDomainClassSimpleName(typeElement)));
            } catch (IOException e) {
                processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, e.getMessage());
            }
        }
        return true;
    }

    protected String guessWriteFileName(TypeElement element) {
        return guessPackageName(element) + "." + guessRepositorySimpleName(element) + "Repository";
    }

    protected String guessPackageName(TypeElement domainType) {
        String fullName = guessDomainClassFullName(domainType);
        return fullName.substring(0, fullName.lastIndexOf("."));
    }

    protected String guessDomainClassFullName(TypeElement element) {
        return element.getQualifiedName().toString();
    }

    protected String guessRepositorySimpleName(TypeElement domainType) {
        return guessDomainClassSimpleName(domainType).replace("PO", "");
    }

    protected String guessDomainClassSimpleName(TypeElement element) {
        return element.getSimpleName().toString();
    }
}
